package example.Test001;

import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ScatterGatherExample {

    public static void main(String[] args) throws Exception {
        // 源文件路径和目标文件路径
        String sourcePath = "source.txt";
        String destPath = "dest.txt";

        // ==================== 第一部分：Scattering Read ====================
        System.out.println("=== 开始 Scattering Read ===");

        // 1. 打开源文件通道（只读）
        RandomAccessFile sourceFile = new RandomAccessFile(sourcePath, "r");
        FileChannel sourceChannel = sourceFile.getChannel();

        // 2. 创建一组Buffer用于接收分散的数据
        ByteBuffer headerBuffer = ByteBuffer.allocate(5);  // 准备存放 "Hello"
        ByteBuffer bodyBuffer = ByteBuffer.allocate(5);    // 准备存放 "World"
        ByteBuffer footerBuffer = ByteBuffer.allocate(10); // 准备存放 "12345"

        ByteBuffer[] scatterBuffers = {headerBuffer, bodyBuffer, footerBuffer};

        // 3. 执行散射读取！
        long totalBytesRead = sourceChannel.read(scatterBuffers);
        System.out.println("Scattering Read 成功，共读取 " + totalBytesRead + " 字节");

        // 4. 将每个Buffer切换为读模式（flip），为Gathering Write做准备
        for (ByteBuffer buffer : scatterBuffers) {
            buffer.flip();
        }

        // 打印读取的内容以便验证
        System.out.println("Header: " + toString(headerBuffer));
        System.out.println("Body: " + toString(bodyBuffer));
        System.out.println("Footer: " + toString(bodyBuffer));

        // 注意：flip()后position回到了0，所以我们需要rewind()才能再次读取数据
        for (ByteBuffer buffer : scatterBuffers) {
            buffer.rewind(); // position重置为0，limit不变，允许再次读取
        }

        // 关闭源通道
        sourceChannel.close();
        sourceFile.close();

        // ==================== 第二部分：Gathering Write ====================
        System.out.println("\n=== 开始 Gathering Write ===");

        // 1. 打开目标文件通道（读写模式，会创建新文件或覆盖已有文件）
        RandomAccessFile destFile = new RandomAccessFile(destPath, "rw");
        FileChannel destChannel = destFile.getChannel();

        // 2. 使用刚才填充好的Buffer数组进行聚集写入
        // 注意：数组中的Buffer必须都处于读模式（position < limit）
        long totalBytesWritten = destChannel.write(scatterBuffers);
        System.out.println("Gathering Write 成功，共写入 " + totalBytesWritten + " 字节");

        // 3. 关闭目标通道
        destChannel.close();
        destFile.close();

        System.out.println("\n文件拷贝完成！请检查 " + destPath + " 文件内容。");
    }

    // 一个辅助方法，将ByteBuffer内容转为String（不影响position）
    private static String toString(ByteBuffer buffer) {
        // 标记当前position
        buffer.mark();
        byte[] bytes = new byte[buffer.remaining()];
        buffer.get(bytes);
        // 重置position到标记点（即原来的位置）
        buffer.reset();
        return new String(bytes);
    }
}